package top.mengchaob.fileserver.netty.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.mengchaob.fileserver.netty.api.FileServiceI;
import top.mengchaob.fileserver.netty.jpa.FileLBRepository;
import top.mengchaob.fileserver.netty.jpa.FileRepository;
import top.mengchaob.fileserver.netty.table.FileDo;
import top.mengchaob.fileserver.netty.table.FileLBDo;
import top.mengchaob.gitManage.jpa.GitFileRepository;
import top.mengchaob.gitManage.table.GitFileDo;
import top.mengchaob.util.ResultBean;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @title：
 * @author: mengchaob
 * @date: 2021年05月12日 14:57
 * @description:
 */
@Service
@Transactional
public class FileService implements FileServiceI {
    @Autowired
    FileLBRepository fileLBRepository;
    @Autowired
    FileRepository fileRepository;
    @Autowired
    GitFileRepository gitFileRepository;
    @Override
    public ResultBean addFileLb(FileLBDo fileLBDo) {
        fileLBRepository.save(fileLBDo);
        return ResultBean.ok("保存成功");
    }

    @Override
    public ResultBean updateFileLb(FileLBDo fileLBDo) {
        fileLBRepository.save(fileLBDo);
        return ResultBean.ok("保存成功");
    }

    @Override
    public ResultBean delFileLb(String lbCode) {
        int i = fileLBRepository.delByLbcode(lbCode);
        int j = fileRepository.delByLbcode(lbCode);
        return ResultBean.ok("删除记录"+i+"条类别，"+j+"条文件数据！");
    }

    @Override
    public ResultBean queryFileLb(String lbCode) {
        // 整体思路：
        // 1、取得所有数据、放入集合List1 （list）
        // 2、将List1所有数据都放入到map（treeMap）中：元素id为键，元素本身对象为值
        // 3、取得顶层节点放入集合List2中（resultList）
        // 4、遍历List1中的所有数据，通过数据的parentId为键在map中取值
        //      1）如果能取到，则说明该元素有父节点
        //           1、判断该父节点下的childList中是否有已经子节点
        //              1、若无：则创建一个集合，将子节点放入
        //              2、若有：则直接将子节点放入即可
        // 5、把放好的数据放回到map中
        // 6、返回List2（resultList）

        // 注意：整个过程将所有数据取出放入list2（resultList）,返回的也是    //list2
        List<FileLBDo> list = null;
        if(lbCode==null){
            list = fileLBRepository.queryAll();
        }else {
            list = fileLBRepository.queryByLbcode(lbCode);
        }
        List<FileLBDo> resultList = new ArrayList<FileLBDo>(); // 存贮顶层的数据
        Map<Object ,Object> treeMap = new HashMap();
        Object itemTree;

        for(int i = 0;i<list.size() && !list.isEmpty();i++){
            itemTree = list.get(i);
            treeMap.put(list.get(i).getLbId(),list.get(i));// 把所有的数据都放到map中


        }
        // 这里也可以用另一种方法，就是拿到集合里的每个元素的父id去数据库中查询，但是，这样与数据库的交互次数就太多了
        // 遍历map得到顶层节点（游离节点也算作顶层节点）
        for(int i =0;i<list.size();i++){
            // 优点1：整个方法，只查询了一次数据库
            // 优点2：不用知道顶层节点的id
            if(!treeMap.containsKey(list.get(i).getPid())){
                // 我们在存储的时候就是将元素的id为键，元素本身为值存入的
                // 以元素的父id为键，在map里取值，若取不到则，对应的元素不存在，即没有父节点，为顶层节点或游离节点
                // 将顶层节点放入list集合
                resultList.add(list.get(i));
            }
        }

        // 循环数据，将数据放到该节点的父节点的children属性中
        for(int i =0 ;i<list.size()&& !list.isEmpty();i++){
            // 数据库中，若一个元素有子节点，那么，该元素的id为子节点的父id
            FileLBDo fileLBDo = (FileLBDo)treeMap.get(list.get(i).getPid());
            if(fileLBDo!=null ){ // 不等于null，也就意味着有父节点
                // 有了父节点，要判断父节点下存贮字节点的集合是否存在，然后将子节点放入
                if(fileLBDo.getFileLBDos() == null){
                    // 判断一个集合是否被创建用null：表示结合还没有被分配内存空间(即还没有被创建)，内存大小自然为null
                    // 用集合的size判断集合中是否有元素，为0，没有元素（集合已经被创建），
                    fileLBDo.setFileLBDos(new ArrayList<FileLBDo>());
                }
                fileLBDo.getFileLBDos().add(list.get(i)); // 添加到父节点的ChildList集合下

                // 这一步其实可以不要，因为我们修改了数据（添加了子节点，然后在将元素放入到map中，
                // 若键相同，map会自动覆盖掉相同的键值对，达到更新map集合中的数据的目的），但是我们
                // 这里只是从map中取值，而并不关心值的子节点（子节点是对象本身自己封装的。这里我们知道
                // 元素从查询后放入map,父节点放入list，然后通过键来在map中取得对象，之后再将修改过的对象重新放入map当中
                // ,我们并没有直接操作list,但是在list中对象的值却是已经修改过了，这就是对象的引用传递，同一个引用对象是通过
                // 地址值来操作对象的，即有不同的引用，但是对象中的属性是已经通过引用的操作而改变的，所以这里一旦修改过后，无论是map中还是list中，再次取值时都已经是更改过后的值了）
                treeMap.put(list.get(i).getPid(),fileLBDo);  // 把放好的数据放回到map中
            }

        }
        return ResultBean.ok(resultList);
    }

    @Override
    public ResultBean addFile(FileDo fileDo) {
        fileRepository.save(fileDo);
        return ResultBean.ok("保存成功");
    }

    @Override
    public ResultBean updateFile(FileDo fileDo) {
        fileRepository.save(fileDo);
        return ResultBean.ok("更新成功！");
    }

    @Override
    public ResultBean delFile(String[] fileIds) {
        fileRepository.deleteByIds(Arrays.asList(fileIds.clone()));
        return ResultBean.ok("删除成功！");
    }

    @Override
    public ResultBean queryFile(String fileId) {
        return ResultBean.ok(fileRepository.findById(fileId));
    }

    @Override
    public ResultBean queryFileByLbCode(String lbCode) {
        return ResultBean.ok(fileRepository.queryByLbcode(lbCode));
    }

    @Override
    public ResultBean getFileLbAndFileInfoList() {
        /**
         * 查询所有文件分类
         */
        ResultBean fileLbInfo  = this.queryFileLb(null);
        /**
         * 查询所有文件
         */
        List<FileDo> fileInfo = fileRepository.findAll();
        Map<String, List<FileDo>> groupByLbCode = fileInfo.stream().collect(Collectors.groupingBy(FileDo::getLbCode));
        List<FileLBDo> fileLBDo = (List<FileLBDo>) fileLbInfo.getData();
        /**
         * 查询存在文件的分支
         */
        List<String> list = this.gitFileRepository.getGitFileDoUseTree();
        for (int i = 0; i < list.size(); i++) {
            FileLBDo tmp = new FileLBDo();
            String branchName = list.get(i);
            tmp.setLbId(branchName);
            tmp.setLbCode(branchName);
            tmp.setLbName(branchName);
            fileLBDo.add(tmp);
        }
        this.putFileInfo(fileLBDo,groupByLbCode);
        fileLBDo = this.fixFileTree(fileLBDo);
        return ResultBean.ok(fileLBDo);
    }
    private void putFileInfo(List<FileLBDo> fileLBDo ,Map<String, List<FileDo>> groupByLbCode){
        fileLBDo.stream().forEach(e->{
            if(e.getFileLBDos()!=null && e.getFileLBDos().size()>0){
                putFileInfo(e.getFileLBDos(),groupByLbCode);
            }else{
                e.setFileDos(groupByLbCode.get(e.getLbCode()));
            }
        });
    }

    /**
     * 将文件类别修改成对应的文件信息格式，方便前端展示
     * @param fileLBDo
     * @return
     */
    private List fixFileTree(List<FileLBDo> fileLBDo){
        if(fileLBDo==null){
            return null;
        }
        List result = new ArrayList(fileLBDo.size());
        fileLBDo.stream().forEach(e->{
            if(e.getFileLBDos()!=null && e.getFileLBDos().size()>0){
                Map map = new HashMap();
                map.put("fileId",e.getLbId());
                map.put("fileDos",fixFileTree(e.getFileLBDos()));
                map.put("fileName",e.getLbName());
                /**
                 * 非文件信息节点
                 */
                map.put("disabled","true");
                result.add(map);
//                result.add(fixFileTree(e.getFileLBDos()));
            }else{
                Map map = new HashMap();
                map.put("fileId",e.getLbId());
                map.put("fileDos",e.getFileDos());
                map.put("fileName",e.getLbName());
                result.add(map);
            }
        });
        return result;
    }
}
